﻿using System;
using System.Collections.Generic;
using System.IO;

namespace CXW.Core
{
    /// <summary>
    /// Class that helps starting up CXW.Core.
    /// </summary>
    /// <remarks>
    /// Initializing CXW.Core requires initializing several static classes
    /// and the <see cref="AddInTree"/>. <see cref="CoreStartup"/> does this work
    /// for you, provided you use it like this:
    /// 1. Create a new CoreStartup instance
    /// 2. (Optional) Set the values of the properties.
    /// 3. Call <see cref="StartCoreServices()"/>.
    /// 4. Add "preinstalled" AddIns using <see cref="AddAddInsFromDirectory"/>
    ///    and <see cref="AddAddInFile"/>.
    /// 5. Call <see cref="RunInitialization"/>.
    /// </remarks>
    public sealed class CoreStartup
    {
        List<string> addInFiles = new List<string>();
        List<string> disabledAddIns = new List<string>();

        string propertiesName;
        string configDirectory;
        string dataDirectory;
        string applicationName;

        /// <summary>
        /// Sets the directory name used for the property service.
        /// Must be set before StartCoreServices() is called.
        /// Use null to use the default path "%ApplicationData%\%ApplicationName%",
        /// where %ApplicationData% is the system setting for
        /// "c:\documents and settings\username\application data"
        /// and %ApplicationName% is the application name you used in the
        /// CoreStartup constructor call.
        /// </summary>
        public string ConfigDirectory
        {
            get { return configDirectory; }
            set { configDirectory = value; }
        }

        /// <summary>
        /// Sets the data directory used to load resources.
        /// Must be set before StartCoreServices() is called.
        /// Use null to use the default path "ApplicationRootPath\data".
        /// </summary>
        public string DataDirectory
        {
            get { return dataDirectory; }
            set { dataDirectory = value; }
        }

        /// <summary>
        /// Creates a new CoreStartup instance.
        /// </summary>
        /// <param name="applicationName">
        /// The name of your application.
        /// This is used as default title for message boxes,
        /// default name for the configuration directory etc.
        /// </param>
        public CoreStartup(string applicationName)
        {
            if (applicationName == null)
                throw new ArgumentNullException("applicationName");
            this.applicationName = applicationName;
            propertiesName = applicationName + ".Properties";

            MessageService.ProductName = applicationName;
        }

        /// <summary>
        /// Find AddIns by searching all .addin files recursively in <paramref name="addInDir"/>.
        /// The AddIns that were found are added to the list of AddIn files to load.
        /// </summary>
        public void AddAddInsFromDirectory(string addInDir)
        {
            if (addInDir == null)
                throw new ArgumentNullException("addInDir");
            addInFiles.AddRange(Directory.GetFiles(addInDir, "*.addin", SearchOption.AllDirectories));
        }

        /// <summary>
        /// Add the specified .addin file to the list of AddIn files to load.
        /// </summary>
        public void AddAddInFile(string addInFile)
        {
            if (addInFile == null)
                throw new ArgumentNullException("addInFile");
            addInFiles.Add(addInFile);
        }

        /// <summary>
        /// Initializes the AddIn system.
        /// This loads the AddIns that were added to the list,
        /// then it executes the <see cref="ICommand">commands</see>
        /// in <c>/Workspace/Autostart</c>.
        /// </summary>
        public void RunInitialization()
        {
            AddInTree.Load(addInFiles, disabledAddIns);

            // run workspace autostart commands
            LoggingService.Info("Running autostart commands...");
            foreach (ICommand command in AddInTree.BuildItems<ICommand>("/Workspace/Autostart", null, false))
            {
                try
                {
                    command.Run();
                }
                catch (Exception ex)
                {
                    // allow startup to continue if some commands fail
                    MessageService.ShowException(ex);
                }
            }
        }

        /// <summary>
        /// Starts the core services.
        /// This initializes the PropertyService and ResourceService.
        /// </summary>
        public void StartCoreServices()
        {
            if (configDirectory == null)
                configDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                                               applicationName);
            PropertyService.InitializeService(configDirectory,
                                              dataDirectory ?? Path.Combine(FileUtility.ApplicationRootPath, "data"),
                                              propertiesName);
            PropertyService.Load();
            ResourceService.InitializeService(Path.Combine(PropertyService.DataDirectory, ""));
        }
    }
}
